import React from 'react';
import _ from 'underscore';

import { Scope } from 'lib/scopeFactory';
import { Warning } from 'lib/components/Notify.jsx';

import { defaultApi, request } from '../../apis/core-util';
import Str from '../../common/Str.js';

const viewValueMapper = item => {
  let {
    filter: value,
    func
  } = item;

  if (func.valueType === 'select' || func.valueType === 'single-select') {
    value = _.isArray(value) ? value : [value];
    return _.map(value, item => item.label);
  } else if (func.valueType === 'input') {
  return [value];
  } else if (func.valueType === 'input-group') {
    return [value.left, value.right];
  }
  // TODO: add more convert logic.
}; // viewValueMapper

export default class EventScope extends Scope {
  constructor(props, context) {
    super(props, context);

    this.item = props.item;
    this.$state = {
      predefinedEvents: [],
      isNew: !props.item,
      inProcessing: false,
      currentEvent: {
        details: props.item ? [] : [
          {
            predefinedEvent: null,
            filters: []
          }
        ],
        name: '',
        cname: ''
      },
      errors: {

      }
    }; // $state

    this.predefinedEventsApi = defaultApi({
      __url: `sd/${ BlueWare.appId }/api/events/all`
    });
  } // constructor

  convertCurrentEvent(target) {
    let currentEvent = {
      name: target.name,
      cname: target.cname,
      details: target.virtual_define
    };

    return currentEvent;
  } // convertCurrentEvent

  $property_changed(payload) {
    _.extend(this.$state.currentEvent, payload.data);

    this.$state.errors = this.validator();

    this.emit();
  } // $property_changed

  $add_event() {
    this.$state.currentEvent.details.push({
      event_name: this.$state.predefinedEvents[0].value,
      filter: {
        relation: 'and',
        conditions: []
      },
      predefinedEvent: this.$state.predefinedEvents.length ? this.$state.predefinedEvents[0] : null,  // 表示新的项默认选中的预定义事件
      filters: [] // 表示当前预定义事件的筛选器集合
    });
    this.emit();
  } // $add_event

  $remove_indexed_event(payload) {
    let data = this.$state.currentEvent.details;
    this.$state.currentEvent.details = [
      ...data.slice(0, payload.index),
      ...data.slice(payload.index + 1)
    ];

    if (!this.$state.currentEvent.details.length) {
      this.$state.currentEvent.details.push({
        predefinedEvent: null,
        filters: []
      });
    }
    this.emit();
  } // $remove_indexed_event

  $remove_self() {
    if (!this.$state.isNew) {
      request(`/mobile/sd/${ BlueWare.appId }/api/event/virtual/${this.item.id}`, 'DELETE')
        .progress(() => {
          this.$state.inProcessing = true;
          this.emit();
        })
        .fail(error => {
          if (error.status >= 400 && error.status < 500) {
            Warning('删除失败');
          } else {
            Warning('网络异常！');
          }
          this.$state.inProcessing = false;
          this.emit();
        })
        .done(data => this.viewInstance.close(true));
    }
  } // $remove_self

  // 验证用户输入是否合法，如果都合法，即返回对象
  // 否则返回对应的错误信息
  validator() {
    let result = {};

    _.each(this.$state.currentEvent, (item, key) => {
      if (_.isString(item)) {
        let fieldName = key === 'name' ? '虚拟事件名' : '虚拟事件显示名';

        if (Str.size(item) === 0) {
          return result[key] = `${fieldName}不能为空`;
        } else if (Str.size(item) > 100) {
          return result[key] = `${fieldName}不能超出100个字符`;
        }

        if (key === 'name') {
          if (! (/^[a-zA-Z_\$]/).test(item)) {
            result[key] = '虚拟事件名只能包含大小写字母数字或_ $，且第一个字符不能是数字';
          }
        }
      }
    });

    return result;
  }

  $save_virtual() {
    if (this.$state.inProcessing) {
      return;
    }

    let errors = this.validator();

    if (_.keys(errors).length === 0) {
      let url = `/mobile/sd/${ BlueWare.appId }/api/event/virtual` + (this.$state.isNew ? '' : `/${this.item.id}`);
      let saveObject = this.saveNewEvent();
      request(url, 'POST', saveObject)
        .progress(() => {
          this.$state.inProcessing = true;
          this.emit();
        })
        .fail(error => {
          if (error.status >= 400 && error.status < 500) {
            Warning(error.status === 409 ? `已经存在该事件，创建虚拟事件"${this.$state.currentEvent.cname}"失败` : `输入参数有误，创建虚拟事件"${this.$state.currentEvent.cname}"失败`);
          } else {
            Warning(`创建虚拟事件"${this.$state.currentEvent.cname}"失败`);
          }
          this.$state.inProcessing = false;
          this.emit();
        })
        .done(data => this.viewInstance.close(true));
    } else {
      this.$state.errors = errors;
      this.emit();
    }
  } // $save_virtual

  saveNewEvent() {
    let target = this.$state.currentEvent;
    let body = {
      name: target.name,
      cname: target.cname
    };

    let events = _.chain(target.details)
                  .filter(item => !!item.predefinedEvent)
                  .map(event => this.convertToSaveFromView(event), this)
                  .value();
    body.virtual_define = events;

    return body;
  } // saveNewEvent

  convertToSaveFromView(event) {
    let result = {
      event_name: event.predefinedEvent.value,
      filter: {
        relation: 'and'
      }
    };

    let conditions = _.chain(event.filters)
                      .filter(item => item.filter)
                      .map(item => {
                        return {
                          field: `event.${event.predefinedEvent.value}.${item.field.value}`,
                          function: item.func.value,
                          params: item.func.valueType === '' ? [] : viewValueMapper(item)
                        }
                      }, this)
                      .value();
    result.filter.conditions = conditions;

    return result;
  } // convertToSaveFromView

  fetch() {
    this.predefinedEventsApi
        .fetch()
        .fail(() => this.$state.predefinedEvents = [])
        .done(data => {
          this.$state.predefinedEvents = _.chain(data)
                                          .filter(item => item.visible && !item.virtual)
                                          .map(item => ({
                                            label: item.cname,
                                            value: item.name,
                                            object: item
                                          }))
                                          .sortBy('label')
                                          .value();
          if (this.$state.isNew) {
            this.$state.currentEvent.details = [
              { event_name: this.$state.predefinedEvents[0].value }
            ];
          } else {
            this.$state.currentEvent = this.convertCurrentEvent(this.item);
          }
        })
        .always(() => this.emit());
  } // fetch

  $load() {
    this.fetch();
  } // $load
}
